﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Autofac;
using Autofac.Core.Lifetime;
using Autofac.Core.Resolving;
using System.Diagnostics;
using Autofac.Configuration.Core;
using Autofac.Configuration;
using Autofac.Core;
using System.Reflection;
using SuperJoe.Framework.Logging;
using Microsoft.Extensions.Configuration;
//using Microsoft.Extensions.Configuration.Xml;


namespace SuperJoe.Framework.Ioc
{
    public class AutofacIocContainer : IIocContainer
    {
        static IContainer container = null;
        static readonly string autofacConfigFile = AppDomain.CurrentDomain.BaseDirectory + "\\autofac.config";

        internal void Init(IList<string> preLoadAssemblyNames)
        {  
            try
            {
                InitInternal(preLoadAssemblyNames);
            }
            catch (Exception ex)
            {
                //WindowsLogUtil.Write("Autofac配置初始化失败, ex:" + ex.ToString(), EventLogEntryType.Error);
                throw ex;
            }
        }

        private static void InitInternal(IList<string> preLoadAssemblyNames)
        {
            var builder = CreateBuilder();

            ConfigurationBuilder configBuilder = new ConfigurationBuilder();
            configBuilder.AddXmlFile(autofacConfigFile);
            var module = new ConfigurationModule(configBuilder.Build());
            builder.RegisterModule(module);

            if (preLoadAssemblyNames != null && preLoadAssemblyNames.Count != 0)
            {
                var assemblies = new Assembly[preLoadAssemblyNames.Count];
                for (var i = 0; i < preLoadAssemblyNames.Count; i++)
                {
                    assemblies[i] = Assembly.Load(preLoadAssemblyNames[i]);
                }

                builder.RegisterAssemblyTypes(assemblies).AsSelf().AsImplementedInterfaces();
            }


            container = builder.Build();
        }

        public IIocContainer RegisterInstance<TService>(TService instance, string name = null) where TService : class
        {
            UpdateContainer((builder) =>
            {
                if (name == null)
                {
                    builder.RegisterInstance<TService>(instance);
                }
                else
                {
                    builder.RegisterInstance<TService>(instance).Named<TService>(name);
                }
            });

            return this;
        }

        public IIocContainer RegisterType<TService, TImplemetation>(string name = null) where TImplemetation : TService
        {

            UpdateContainer((builder) =>
            {
                var register = builder.RegisterType<TImplemetation>().As<TService>();

                if (name != null)
                {
                    register = register.Named<TService>(name);
                }
            });

            return this;
        }

    
        public object Resolve(Type type, string name = null, IEnumerable<ConstructorParameter> parameters = null)
        {
            if (name == null)
            {
                return container.Resolve(type);
            }
            else
            {
                return container.ResolveNamed(name, type);
            }
        }

        public T Resolve<T>(string name = null, IEnumerable<ConstructorParameter> parameters = null)
        {
            List<Parameter> tmpParameters = null;

            if (parameters != null)
            {
                tmpParameters = new List<Parameter>();
                foreach (var item in parameters)
                {
                    if (item.GetType() == typeof(NamedContructorParameter))
                    {
                        tmpParameters.Add(new NamedParameter(((NamedContructorParameter)item).Name, item.Value));
                    }
                    else
                    {
                        tmpParameters.Add(new TypedParameter(((TypedConstructorParameter)item).Type, item.Value));
                    }
                }
            }

            if (name == null)
            {
                if (tmpParameters == null)
                {
                    return container.Resolve<T>();
                }
                else
                {
                    return container.Resolve<T>(tmpParameters);
                }
            }
            else
            {
                if (tmpParameters == null)
                {
                    return container.ResolveNamed<T>(name);
                }
                else
                {
                    return container.ResolveNamed<T>(name, tmpParameters);
                }
            }
        }

        public IEnumerable<T> ResolveAll<T>()
        {
            return container.Resolve<IEnumerable<T>>();
        }

        public static void UpdateContainer(Action<ContainerBuilder> register)
        {
            var builder = CreateBuilder();
            register(builder);
            builder.Update(container);
        }

        public static IContainer Container
        {
            get { return container; }
        }

        private static ContainerBuilder CreateBuilder()
        {
            return new ContainerBuilder();
        }

        public IIocContainer RegisterType<TImplemetation>(string name = null)
        {
            UpdateContainer((builder) =>
            {
                var register = builder.RegisterType<TImplemetation>().AsImplementedInterfaces().AsSelf();

                if (name != null)
                {
                    register = register.Named<TImplemetation>(name);
                }

            });

            return this;
        }

     
    }
}
